#include"Task.hpp"
#include <pthread.h>
#include<vector>
#include<queue>
#define NUMBER 50
class ThreadPool
{
private:
    queue<Task> task_queue;
    pthread_cond_t cond;
    pthread_mutex_t lock;
    int num;
    static ThreadPool* tp;
    bool stop;
    vector<pthread_t>pthreads;
public:
    ThreadPool(int Num=NUMBER)
    :num(Num)
    ,stop(false)
    {
        pthread_mutex_init(&lock,nullptr);
        pthread_cond_init(&cond,nullptr);
        InitialThreadPool();
    }
    ~ThreadPool()
    {
        pthread_mutex_destroy(&lock);
        pthread_cond_destroy(&cond);
        for(int i=0;i<num;i++)
        {
            pthread_join(pthreads[i],nullptr);
        }
    }
    static void* ThreadRoutine(void*args)
    {
        ThreadPool* tp=(ThreadPool*)args;
        bool stop=tp->stop;
        while(!stop)
        {
            pthread_mutex_lock(&tp->lock);
            while (tp->Empty())
            {
                pthread_cond_wait(&tp->cond, &tp->lock);
            }
            pthread_mutex_unlock(&tp->lock);
            Task task = tp->PopTask();
            task.ProcessOn();
        }
        return nullptr;
    }
    static ThreadPool *getinstance(int num)
    {
        static pthread_mutex_t _mutex=PTHREAD_MUTEX_INITIALIZER;
        if(tp==nullptr)
        {
           pthread_mutex_lock(&_mutex);
           if(tp==nullptr)
           {
                tp=new ThreadPool(num);
           }
           pthread_mutex_unlock(&_mutex);
        }
        return tp;
    }
    void InitialThreadPool()
    {
        for(int i=0;i<num;i++)
        {
            pthread_t t;
            pthreads.push_back(t);
            pthread_create(&pthreads[i],nullptr,ThreadRoutine,this);
        }
    }
    void PushTask(const Task& task)
    {
        pthread_mutex_lock(&lock);
        task_queue.push(task);
        pthread_mutex_unlock(&lock);
        pthread_cond_signal(&cond);
    }
    Task PopTask()
    {
        Task task;
         pthread_mutex_lock(&lock);
        task=task_queue.front();
        task_queue.pop();
        pthread_mutex_unlock(&lock);
        return task;
    }
    bool Empty()
    {
       return task_queue.empty();
    }
};
ThreadPool*ThreadPool:: tp=nullptr;